package com.jxc.wiki.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.jxc.wiki.entity.Content;
import com.jxc.wiki.entity.Doc;
import com.jxc.wiki.entity.DocExample;
import com.jxc.wiki.custException.BusinessException;
import com.jxc.wiki.custException.BusinessExceptionCode;
import com.jxc.wiki.mapper.ContentMapper;
import com.jxc.wiki.mapper.DocMapper;
import com.jxc.wiki.mapper.DocMapperCust;
import com.jxc.wiki.request.DocQueryParamReq;
import com.jxc.wiki.request.DocSaveParamReq;
import com.jxc.wiki.response.DocQueryParamResp;
import com.jxc.wiki.response.PageParamResp;
import com.jxc.wiki.service.DocService;
import com.jxc.wiki.service.WsService;
import com.jxc.wiki.util.CopyClassOrListUtil;
import com.jxc.wiki.util.RedisUtil;
import com.jxc.wiki.util.RequestContextUtil;
import com.jxc.wiki.util.SnowFlakeUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.util.List;

@Service
public class DocServiceImpl implements DocService {

    private static final Logger LOG = LoggerFactory.getLogger(DocServiceImpl.class);

    @Resource
    private DocMapper mapper;

    @Resource
    private ContentMapper contentMapper;

    @Resource
    private DocMapperCust docMapperCust;

    @Resource
    private SnowFlakeUtil snowFlakeUtil;

    @Resource
    public RedisUtil redisUtil;

    @Resource
    public WsService wsService;

//    @Resource
//    private RocketMQTemplate rocketMQTemplate;

    public List<DocQueryParamResp> all(Long ebookId){

        DocExample docExample = new DocExample();
        docExample.createCriteria().andEbookIdEqualTo(ebookId);
        // 按sort字段排序
        docExample.setOrderByClause("sort asc");

        List<Doc> docList = mapper.selectByExample(docExample);

        List<DocQueryParamResp> docRespList = CopyClassOrListUtil.copyList(docList, DocQueryParamResp.class);

        return docRespList;
    }

    // 保存功能,通过插入一条新的数据或者更新一条新的数据实现
    /* @Transactional的作用是加事务，让数据注入两张表时数据能够同步，注意：@Transactional注解和@Async注解一样，
      写在方法上面时需要在不同类里调用这个有这两个注解的方法才能让注解生效 */
    @Transactional
    public void save(DocSaveParamReq req){
        Doc doc = CopyClassOrListUtil.copy(req,Doc.class);
        Content content = CopyClassOrListUtil.copy(req, Content.class);

        if (ObjectUtils.isEmpty(req.getId())){

            // 如果id的值为空，则为新增数据,用雪花算法生成id，并设置为doc的id
            doc.setId(snowFlakeUtil.nextId());
            // 将阅读数和点赞数初始化为0，不然就会被置为null，无法进行自加
            doc.setViewCount(0);
            doc.setVoteCount(0);
            mapper.insert(doc);

            content.setId(doc.getId());
            contentMapper.insert(content);
        }else {
            // 如果id的值不为空，则为修改数据
            mapper.updateByPrimaryKey(doc);
            int count = contentMapper.updateByPrimaryKeyWithBLOBs(content);
            if (count == 0){
                contentMapper.insert(content);
            }
        }
    }

    public void delete(Long id){
        mapper.deleteByPrimaryKey(id);
    }

    public void delete(List<String> ids){
        DocExample docExample = new DocExample();
        DocExample.Criteria criteria = docExample.createCriteria();
        criteria.andIdIn(ids);
        mapper.deleteByExample(docExample);
    }

    public PageParamResp<DocQueryParamResp> list(DocQueryParamReq req){


        // 实现输入名字查询电子书的功能，用到了模糊查询
        DocExample docExample = new DocExample();
        DocExample.Criteria criteria = docExample.createCriteria();
        docExample.setOrderByClause("sort asc");
        PageHelper.startPage(req.getPage(),req.getSize());
        List<Doc> docList = mapper.selectByExample(docExample);
        // 打印分页情况日志
        PageInfo<Doc> pageInfo = new PageInfo<>(docList);
        LOG.info("总行数：{}", pageInfo.getTotal());
        LOG.info("总页数：{}", pageInfo.getPages());
//        // 把类型为Doc的集合的值拷贝到类型为DocResp的集合里
//        List<DocResp> docRespList = new ArrayList<>();
//        for (Doc doc : docList) {
//            DocResp docResp = new DocResp();
//            // BeanUtils工具类，可以把doc的值快速拷贝给docResp
//            BeanUtils.copyProperties(doc,docResp);
//            docRespList.add(docResp);
//        }

        // 自定义Copy工具类(运用了反射的知识)快速拷贝
        List<DocQueryParamResp> docRespList = CopyClassOrListUtil.copyList(docList, DocQueryParamResp.class);

        PageParamResp<DocQueryParamResp> pageParamResp = new PageParamResp<>();
        pageParamResp.setTotal(pageInfo.getTotal());
        pageParamResp.setList(docRespList);
        return pageParamResp;
    }

    public String findContent(Long id){
        Content content = contentMapper.selectByPrimaryKey(id);
        // 文档被浏览一次，观看数就加一
        docMapperCust.increaseViewCount(id);
        if (ObjectUtils.isEmpty(content)){
            return "";
        }else {
            return content.getContent();
        }
    }

    public void vote(Long id){
        // docMapperCust.increaseVoteCount(id);
        // 点赞校验，用远程IP+doc.id作为key（远程id是通过nginx反向代理获取的），24小时内不能重复
        String ip = RequestContextUtil.getRemoteAddr();
        if (redisUtil.validateRepeat("DOC_VOTE_" + id + "_" + ip, 5000)) {
            // 如果校验时key不存在,则点赞数+1
            docMapperCust.increaseVoteCount(id);
        } else {
            throw new BusinessException(BusinessExceptionCode.VOTE_REPEAT);
        }

        // 推送消息
        Doc doc = mapper.selectByPrimaryKey(id);
        String logId = MDC.get("LOG_ID");
        wsService.sendInfo("【" + doc.getName() + "】被点赞！",logId);
//        rocketMQTemplate.convertAndSend("VOTE_TOPIC", "【" + doc.getName() + "】被点赞！");

    }

    public void updateEbookInfo(){
        docMapperCust.updateEbookInfo();
    }
}
